package com.guang.service;

import com.alibaba.fastjson.JSON;
import com.guang.common.RedisKeyPrefixConst;
import com.guang.common.RedisUtil;
import com.guang.dao.ProductDao;
import com.guang.model.Product;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 首先在维护的热点数据的时候可以来存储一天时间！没有必要进行永久存储
 * <p>
 * 1、缓存击穿问题：一大批请求进来的时候，防止缓存中都找不到，直接找到了数据库中去！造成数据库的压力很大！这是不可取的
 * 2、缓存击穿问题<====>缓存失效问题
 */
@Service
public class ProductService0 {

    @Autowired
    private ProductDao productDao;

    @Autowired
    private RedisUtil redisUtil;

    public static final Integer PRODUCT_CACHE_TIMEOUT = 60 * 60 * 24;
    public static final String EMPTY_CACHE = "{}";
    public static Map<String, Product> productMap = new ConcurrentHashMap<>();

    /**
     * 创建商品
     *
     * @param product
     * @return
     */
    @Transactional
    public Product create(Product product) {
        Product productResult = productDao.create(product);
        redisUtil.set(RedisKeyPrefixConst.PRODUCT_CACHE + productResult.getId(), JSON.toJSONString(productResult));
        return productResult;
    }

    /**
     * 简单使用过程中可能会出现的问题！
     *
     * @param product
     * @return
     */
    @Transactional
    public Product update(Product product) {
        Product productResult = null;
        productResult = productDao.update(product);
        redisUtil.set(RedisKeyPrefixConst.PRODUCT_CACHE + productResult.getId(), JSON.toJSONString(productResult));
        // 更新的时候设置一下随机时间！
        redisUtil.expire(RedisKeyPrefixConst.PRODUCT_CACHE + productResult.getId(), genProductCacheTimeout(), TimeUnit.SECONDS);
        return productResult;
    }

    /**
     * 根据商品ID来进行查询对应的商品
     *
     * @param productId 商品ID
     * @return 返回缓存中的商品
     * @throws InterruptedException
     */
    public Product get(Long productId) throws InterruptedException {
        Product product = null;
        String productCacheKey = RedisKeyPrefixConst.PRODUCT_CACHE + productId;
        String productStr = redisUtil.get(productCacheKey);
        if (!StringUtils.isEmpty(productStr)) {
            product = JSON.parseObject(productStr, Product.class);
            // 每次查询的时候都可以给来当前key设置一下时间，防止当前缓存失效-------->实现了简单的冷热分离！！！
            redisUtil.expire(productCacheKey, PRODUCT_CACHE_TIMEOUT, TimeUnit.SECONDS);
            return product;
        }
        product = productDao.get(productId);
        if (product != null) {
            // 返回之前设置到redis中来！并且设置超时时间
            redisUtil.set(productCacheKey, JSON.toJSONString(product));
            redisUtil.expire(productCacheKey, PRODUCT_CACHE_TIMEOUT, TimeUnit.SECONDS);
        }
        return product;
    }


    private Integer genProductCacheTimeout() {
        return PRODUCT_CACHE_TIMEOUT + new Random().nextInt(5) * 60 * 60;
    }

    private Integer genEmptyCacheTimeout() {
        return 60 + new Random().nextInt(30);
    }

    private Product getProductFromCache(String productCacheKey) {
        Product product = productMap.get(productCacheKey);
        if (product != null) {
            return product;
        }

        String productStr = redisUtil.get(productCacheKey);
        if (!StringUtils.isEmpty(productStr)) {
            if (EMPTY_CACHE.equals(productStr)) {
                redisUtil.expire(productCacheKey, genEmptyCacheTimeout(), TimeUnit.SECONDS);
                return new Product();
            }
            product = JSON.parseObject(productStr, Product.class);
            redisUtil.expire(productCacheKey, genProductCacheTimeout(), TimeUnit.SECONDS); //读延期
        }
        return product;
    }

}